//
// DRV8311P.C
// Created by Xiaoyun on 2023/3/22.
//

#include "adc.h"
#include "drv8311p.h"

/*-------------------DRV_ADC-------------------*/
static uint16_t drv_adc_dma_buff[DRV_ADC_QUEUE_LEN * N_ADC_CHANNEL];
static uint16_t drv_adc_buff[N_ADC_CHANNEL];

/**
 *
 * @param adc_dma_buff : uint16_t the buffer for adc data
 * @param dma_buff_size : size of buffer for adc data
 * @note need user to implement the function
 */
__weak void DRV_ADC_DMA_Init(uint16_t *adc_dma_buff, uint8_t dma_buff_size) {

}
/**
 * @note need user to implement the function
 */
__weak void DRV_PWM_Init() {

}
/**
 * @note need user to implement the function
 */
__weak void DRV_SPI_Init() {

}
/**
 * @note need user to implement the function
 */
__weak void DRV_ADC_Start_DMA(uint16_t *adc_dma_buff, uint8_t dma_buff_size){

}
/**
 * @note need user to implement the function
 */
__weak void DRV_ADC_Stop_DMA(){

}
/**
 * @brief drv8311 initialization function
 */
void DRV_Init() {
  /* ADC Init */
  DRV_ADC_DMA_Init(drv_adc_dma_buff, DRV_ADC_QUEUE_LEN * N_ADC_CHANNEL);
  DRV_PWM_Init();
  DRV_SPI_Init();
}

/**
 * @brief drv8311 ADC DMA start function
 */
void DRV_ADC_Start(){
  DRV_ADC_Start_DMA(drv_adc_dma_buff, DRV_ADC_QUEUE_LEN * N_ADC_CHANNEL);
}
/**
 * @brief drv8311 ADC DMA stop function
 */
void DRV_ADC_Stop(){
  DRV_ADC_Stop_DMA();
}
/**
 *
 * @brief Get ADC average results in buffer
 * @param channel The channel of DRV8311 Channel ADC
 * @return 12-bits
 */
uint16_t DRV_Get_ADC(DRV_Channel_ADC channel) {
  return drv_adc_buff[channel];
}

/**
 *
 * @brief Calculate ADC average results to buffer
 * @return 12-bits
 * @note need to put in the adc complete callback function
 */
void DRV_Mean_Cal(){
  for(int channel=0;channel<N_ADC_CHANNEL;channel++){
    drv_adc_buff[channel] = 0;
    for (int i = 0; i < DRV_ADC_QUEUE_LEN; i++)
      drv_adc_buff[channel] += drv_adc_dma_buff[i * N_ADC_CHANNEL + channel];
    drv_adc_buff[channel] /= DRV_ADC_QUEUE_LEN;
  }
}


/*-------------------DRV SPI-------------------*/

/**
 *
 * @param drv_write_buff : buffer for data sending to slave
 * @param drv_read_buff : buffer for store data form slave
 * @param num : number of data in uint16_t
 * @note need user to implement the function
 */
__weak void DRV_tSPI_TransmitReceive(uint16_t *drv_write_buff, uint16_t *drv_read_buff, uint8_t num) {

}

/**
 * @brief Internal function used to generate the head of tSPI
 * @param rw : read or write
 * @param drv_reg : register address
 * @param device_id : DRV_DEVICE_ID_x
 * @return
 */
static uint16_t DRV_tSPI_HEAD(DRV_RW_e rw, DRV_REGS_ADDR_e drv_reg, uint8_t device_id) {
  return (rw | (((uint16_t) drv_reg) << 3) | (((uint16_t) device_id) << 11));
}

/**
 *
 * @param addr : drv8311 register address in DRV_REGS_ADDR_e
 * @param device_id : DRV_DEVICE_ID_x
 * @return Data of Register
 */
uint16_t DRV_Get_REG(DRV_REGS_ADDR_e addr, uint8_t device_id) {
  uint16_t cmd[2] = {0};
  uint16_t rcv[2] = {0};
  cmd[0] = DRV_tSPI_HEAD(DRV_Read, addr, device_id);
  DRV_tSPI_TransmitReceive(cmd, rcv, 2);
  volatile uint8_t t=20;
  while(t--);
  return rcv[1];
}

/**
 *
 * @brief Read 4 continuous status register data
 * @param dev_sts : DEV_STS1_t*
 * @param ot_sts : OT_STS_t*
 * @param sup_sts : SUP_STS_t*
 * @param drv_sts : DRV_STS_t*
 * @param sys_sts : SYS_STS_t*
 * @param device_id : DRV_DEVICE_ID_x
 */
void DRV_Get_STS_Datas(DEV_STS1_t *dev_sts, OT_STS_t *ot_sts, SUP_STS_t *sup_sts, DRV_STS_t *drv_sts, SYS_STS_t *sys_sts,
                  uint8_t device_id) {
  uint16_t cmd[5] = {0};
  uint16_t rcv[5] = {0};
  uint16_t *p = rcv;
  cmd[0] = DRV_tSPI_HEAD(DRV_Read, OT_STS, device_id);
  DRV_tSPI_TransmitReceive(cmd, rcv, 5);
  *dev_sts = *(DEV_STS1_t *) (p++);
  *ot_sts = *(OT_STS_t *) (p++);
  *sup_sts = *(SUP_STS_t *) (p++);
  *drv_sts = *(DRV_STS_t *) (p++);
  *sys_sts = *(SYS_STS_t *) (p++);
  volatile uint8_t t=20;
  while(t--);
}

/**
 *
 * @brief Set the FLT_MODE register
 * @param flt_mode : FLT_MODE_t*
 * @param device_id : DRV_DEVICE_ID_x
 */
void DRV_Set_FLT_MODE(FLT_MODE_t *flt_mode, uint16_t device_id) {
  uint16_t cmd[2] = {0};
  uint16_t rcv[2] = {0};
  cmd[0] = DRV_tSPI_HEAD(DRV_Write, FLT_MODE, device_id);
  cmd[1] = *(uint16_t *) flt_mode;
  DRV_tSPI_TransmitReceive(cmd, rcv, 2);
}

/**
 *
 * @brief Set the SYSF_CTRL register
 * @param sysf_ctrl : SYSF_CTRL_t*
 * @param device_id : DRV_DEVICE_ID_x
 */
void DRV_Set_SYSF_CTRL(SYSF_CTRL_t *sysf_ctrl, uint16_t device_id) {
  uint16_t cmd[2] = {0};
  uint16_t rcv[2] = {0};
  cmd[0] = DRV_tSPI_HEAD(DRV_Write, SYSF_CTRL, device_id);
  cmd[1] = *(uint16_t *) sysf_ctrl;
  DRV_tSPI_TransmitReceive(cmd, rcv, 2);
}

/**
 *
 * @brief Set the DRVF_CTRL register
 * @param drvf_ctrl : DRVF_CTRL_t*
 * @param device_id : DRV_DEVICE_ID_x
 */
void DRV_Set_DRVF_CTRL(DRVF_CTRL_t *drvf_ctrl, uint16_t device_id) {
  uint16_t cmd[2] = {0};
  uint16_t rcv[2] = {0};
  cmd[0] = DRV_tSPI_HEAD(DRV_Write, DRVF_CTRL, device_id);
  cmd[1] = *(uint16_t *) drvf_ctrl;
  DRV_tSPI_TransmitReceive(cmd, rcv, 2);
}

/**
 *
 * @brief Set the FLT_TCTR register
 * @param flt_tctrl : FLT_TCTRL_t*
 * @param device_id : DRV_DEVICE_ID_x
 */
void DRV_Set_FLT_TCTRL(FLT_TCTRL_t *flt_tctrl, uint16_t device_id) {
  uint16_t cmd[2] = {0};
  uint16_t rcv[2] = {0};
  cmd[0] = DRV_tSPI_HEAD(DRV_Write, FLT_TCTRL, device_id);
  cmd[1] = *(uint16_t *) flt_tctrl;
  DRV_tSPI_TransmitReceive(cmd, rcv, 2);
}

/**
 *
 * @brief Clear Fault Flag
 * @param device_id : DRV_DEVICE_ID_x
 */
void DRV_FLT_Clear(uint16_t device_id) {
  uint16_t cmd[2] = {0};
  uint16_t rcv[2] = {0};
  cmd[0] = DRV_tSPI_HEAD(DRV_Write, FLT_CLR, device_id);
  cmd[1] = 0x8001;
  DRV_tSPI_TransmitReceive(cmd, rcv, 2);
}

/**
 *
 * @brief Set PWM period, the freq of DRV8311 is f=20M
 * @param pwmg_period : 12bit of uint16_t
 * @param device_id : DRV_DEVICE_ID_x
 * @details
 * UP/DOWM Mode period=pwmg_period*2/20M \n
 * UP Mode or DOWM Mode period=pwmg_period/20M
 */
void DRV_Set_PWMG_Period(uint16_t pwmg_period, uint16_t device_id) {
  pwmg_period = (pwmg_period & 0x0fff);
  uint16_t cmd[2] = {0};
  uint16_t rcv[2] = {0};
  cmd[0] = DRV_tSPI_HEAD(DRV_Write, PWMG_PERIOD, device_id);
  cmd[1] = pwmg_period;
  DRV_tSPI_TransmitReceive(cmd, rcv, 2);
}

/**
 *
 * @brief Set the PWM duty of three phase
 * @param pwmg_A_duty : 12bit of uint16_t
 * @param pwmg_B_duty : 12bit of uint16_t
 * @param pwmg_C_duty : 12bit of uint16_t
 * @param device_id : DRV_DEVICE_ID_x
 */
void DRV_Set_PWMG_Duty(uint16_t pwmg_A_duty, uint16_t pwmg_B_duty, uint16_t pwmg_C_duty, uint16_t device_id) {
  uint16_t cmd[4] = {0};
  uint16_t rcv[4] = {0};
  cmd[0] = DRV_tSPI_HEAD(DRV_Write, PWMG_A_DUTY, device_id);
  cmd[1] = (pwmg_A_duty & 0x8fff);
  cmd[2] = (pwmg_B_duty & 0x8fff);
  cmd[3] = (pwmg_C_duty & 0x8fff);
  DRV_tSPI_TransmitReceive(cmd, rcv, 4);
}

/**
 *
 * @brief Set the PWM duty of three phase and pwm state
 * @param pwmg_A_duty : 12bit of uint16_t
 * @param pwmg_B_duty : 12bit of uint16_t
 * @param pwmg_C_duty : 12bit of uint16_t
 * @param pwm_state : PWM_STATE_t*
 * @param device_id : DRV_DEVICE_ID_x
 */
void DRV_Set_PWMG_Duty_State(uint16_t pwmg_A_duty, uint16_t pwmg_B_duty, uint16_t pwmg_C_duty,PWM_STATE_t* pwm_state, uint16_t device_id) {
  uint16_t cmd[5] = {0};
  uint16_t rcv[5] = {0};
  cmd[0] = DRV_tSPI_HEAD(DRV_Write, PWMG_A_DUTY, device_id);
  cmd[1] = (pwmg_A_duty & 0x8fff);
  cmd[2] = (pwmg_B_duty & 0x8fff);
  cmd[3] = (pwmg_C_duty & 0x8fff);
  cmd[4] = ((*(uint16_t*)pwm_state));
  DRV_tSPI_TransmitReceive(cmd, rcv, 4);
}

/**
 * @brief Set the PWM_STATE register
 * @param pwm_state : PWM_STATE_t*
 * @param device_id : DRV_DEVICE_ID_x
 */
void DRV_Set_PWM_STATE(PWM_STATE_t *pwm_state, uint16_t device_id) {
  uint16_t cmd[2] = {0};
  uint16_t rcv[2] = {0};
  cmd[0] = DRV_tSPI_HEAD(DRV_Write, PWM_STATE, device_id);
  cmd[1] = *(uint16_t *) pwm_state;
  DRV_tSPI_TransmitReceive(cmd, rcv, 2);
}

/**
 * @brief Set the PWMG_CTRL register
 * @param pwmg_ctrl : PWMG_CTRL_t*
 * @param device_id : DRV_DEVICE_ID_x
 */
void DRV_Set_PWMG_CTRL(PWMG_CTRL_t *pwmg_ctrl, uint16_t device_id) {
  uint16_t cmd[2] = {0};
  uint16_t rcv[2] = {0};
  cmd[0] = DRV_tSPI_HEAD(DRV_Write, PWMG_CTRL, device_id);
  cmd[1] = *(uint16_t *) pwmg_ctrl;
  DRV_tSPI_TransmitReceive(cmd, rcv, 2);
}

/**
 *
 * @brief Set the PWM_CTRL1 register
 * @param pwm_ctrl1 : PWM_CTRL1_t*
 * @param device_id : DRV_DEVICE_ID_x
 */
void DRV_Set_PWM_CTRL1(PWM_CTRL1_t *pwm_ctrl1, uint16_t device_id) {
  uint16_t cmd[2] = {0};
  uint16_t rcv[2] = {0};
  cmd[0] = DRV_tSPI_HEAD(DRV_Write, PWM_CTRL1, device_id);
  cmd[1] = *(uint16_t *) pwm_ctrl1;
  DRV_tSPI_TransmitReceive(cmd, rcv, 2);
}

/**
 *
 * @brief Set the DRV_CTRL register
 * @param drv_ctrl : DRV_CTRL_t*
 * @param device_id : DRV_DEVICE_ID_x
 */
void DRV_Set_DRV_CTRL(DRV_CTRL_t *drv_ctrl, uint16_t device_id) {
  uint16_t cmd[2] = {0};
  uint16_t rcv[2] = {0};
  cmd[0] = DRV_tSPI_HEAD(DRV_Write, DRV_CTRL, device_id);
  cmd[1] = *(uint16_t *) drv_ctrl;
  DRV_tSPI_TransmitReceive(cmd, rcv, 2);
}

/**
 *
 * @brief Set the CSA_CTRL register
 * @param csa_ctrl : CSA_CTRL_t*
 * @param device_id : DRV_DEVICE_ID_x
 */
void DRV_Set_CSA_CTRL(CSA_CTRL_t *csa_ctrl, uint16_t device_id) {
  uint16_t cmd[2] = {0};
  uint16_t rcv[2] = {0};
  cmd[0] = DRV_tSPI_HEAD(DRV_Write, CSA_CTRL, device_id);
  cmd[1] = *(uint16_t *) csa_ctrl;
  DRV_tSPI_TransmitReceive(cmd, rcv, 2);
}

/**
 *
 * @brief Set the SYS_CTRL register
 * @param sys_ctrl : SYS_CTRL_t*
 * @param device_id : DRV_DEVICE_ID_x
 */
void DRV_Set_SYS_CTRL(SYS_CTRL_t *sys_ctrl, uint16_t device_id) {
  uint16_t cmd[2] = {0};
  uint16_t rcv[2] = {0};
  cmd[0] = DRV_tSPI_HEAD(DRV_Write, SYS_CTRL, device_id);
  cmd[1] = *(uint16_t *) sys_ctrl;
  DRV_tSPI_TransmitReceive(cmd, rcv, 2);
}